package sub1;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.FileNotFoundException;import java.io.File;import java.io.IOException;import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.xml.bind.JAXBException;

import exceptions.FailureConnectionException;
import exceptions.NotFoundException;
import exceptions.TestException;

/**
 * 
 * GUI for the client
 * @see Client
 * @author Magali Moulin, Pierre Labiausse
 * @version 1
 */
public class ClientUI extends JFrame implements ActionListener, WindowListener, Observer {
	
	/**
	 * Main method of the client side: Create a new GUI. 
	 * @param args
	 */
	public static void main(String[] args){
		new ClientUI();
	}
	
	private final int FILE_I_SHARE = 0, FILE_ALL_SHARE = 1, PEER_ON_SERVER = 2, SEARCH = 3;
	private JMenuItem menuQuit, menuParameters, menuShareByMe, menuShareByAll, menuPeerOnTheServer, menuSearch;
	private JButton btnSubmitSearch;
	private JTextField txtSearch;
	private Client client;
	private ExecutorService executor;
	private JLabel lblStatus, lblStatusDownload;
	private JPanel panel, centerPanel = new JPanel();
	private int toDisplay = FILE_I_SHARE;
	
	/**
	 * Constructor of this class. Create the GUI with different components. 
	 */
	public ClientUI(){
		this.client = new Client();
		client.addObserver(this);
		// Construct the window
		this.setSize(new Dimension(500, 500));
		this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
		this.addWindowListener(this); // To Force to client to unregister before quitting
		panel = new JPanel();
		this.setContentPane(panel);
		panel.setLayout(new BorderLayout());
		panel.setPreferredSize(new Dimension(400,400));
		
		// Construct the menu bar
		JMenuBar menuBar = new JMenuBar();
		menuQuit = new JMenuItem("Quit");
		menuQuit.addActionListener(this);
		menuBar.add(menuQuit);
		menuParameters = new JMenuItem("Parameters");
		menuParameters.addActionListener(this);
		menuBar.add(menuParameters);
		JMenu menuDisplay = new JMenu("Display");
		menuShareByMe = new JMenuItem("Files I share");
		menuShareByMe.addActionListener(this);
		menuDisplay.add(menuShareByMe);
		menuShareByAll = new JMenuItem("Files shared on the server");
		menuShareByAll.addActionListener(this);
		menuDisplay.add(menuShareByAll);
		menuPeerOnTheServer = new JMenuItem("Peers on the server");
		menuPeerOnTheServer.addActionListener(this);
		menuDisplay.add(menuPeerOnTheServer);
		menuSearch = new JMenuItem("Search");
		menuSearch.addActionListener(this);
		menuDisplay.add(menuSearch);
		menuBar.add(menuDisplay);
		panel.add(menuBar, BorderLayout.NORTH);
		
		// Add the status label to the panel
		lblStatus = new JLabel("Files are not shared ("+client.getSharedFiles().size()+" files)");
		panel.add(lblStatus, BorderLayout.SOUTH);
		
		// In the middle, display the list of files shared (or at least in the shared folder)
		centerPanel.setLayout(new BorderLayout());
		centerPanel();
		panel.add(centerPanel, BorderLayout.CENTER, 0);
		
		// Create the executor
		executor = Executors.newFixedThreadPool(1);
		
		// Try registering with the default server
		executor.execute(new Runnable() {
			
			@Override
			public void run() {
				try {
					System.out.println("here");
					client.share(client.getServerAddress(), client.getServerPort());
					System.out.println("there");
				} catch (FailureConnectionException e) {
					e.printStackTrace();
				}
			}
		});
		this.setVisible(true);
		
	}

	private void centerPanel() {
		centerPanel.removeAll();
		if(toDisplay == FILE_I_SHARE){
			centerPanel.add(new JLabel("Files in the shared directory : "), BorderLayout.NORTH);
			JPanel _panel = new JPanel();
			_panel.setLayout(new GridLayout(0, 2));
			for(String filename : client.getSharedFiles()){
				_panel.add(new JLabel("* "+filename));
			}
			centerPanel.add(_panel, BorderLayout.CENTER);
			pack();
			repaint();
		}
		if(toDisplay == FILE_ALL_SHARE){
			executor.execute(new Runnable() {
				
				@Override
				public void run() {
					ArrayList<String> fileShared = client.serverStats(0);
					centerPanel.add(new JLabel("Files shared on the server : "), BorderLayout.NORTH);
					JPanel _panel = new JPanel();
					_panel.setLayout(new GridLayout(0, 2));
					for(String filename : fileShared){
						_panel.add(new JLabel("* "+filename));
					}
					centerPanel.add(_panel, BorderLayout.CENTER);
					pack();
					repaint();
				}
			});
		}
		if(toDisplay == PEER_ON_SERVER){
			executor.execute(new Runnable() {
				
				@Override
				public void run() {
					ArrayList<String> peers = client.serverStats(1);
					centerPanel.add(new JLabel("Peers on the server : "), BorderLayout.NORTH);
					JPanel _panel = new JPanel();
					_panel.setLayout(new GridLayout(0, 2));
					for(String peer : peers){
						_panel.add(new JLabel("* "+peer), BorderLayout.CENTER);
					}
					centerPanel.add(_panel);
					pack();
					repaint();
				}
			});
		}
		if(toDisplay == SEARCH){
			lblStatusDownload = new JLabel();
			JPanel _panel = new JPanel();
			_panel.add(new JLabel("Search : "));
			txtSearch = new JTextField();
			txtSearch.setColumns(20);
			_panel.add(txtSearch);
			btnSubmitSearch = new JButton("Search");
			btnSubmitSearch.addActionListener(this);
			getRootPane().setDefaultButton(btnSubmitSearch);
			_panel.add(btnSubmitSearch);
			centerPanel.add(_panel, BorderLayout.NORTH);
			
			if(client.getSearchRequest() != null){
				JPanel _panelResult = new JPanel();
				_panelResult.setLayout(new GridLayout(0, 1));
				_panelResult.add(new JLabel("Result for : "+client.getSearchRequest()));
				for(final String filename : client.getSearchResult().keySet()){
					JPanel _pnl = new JPanel();
					_pnl.add(new JLabel(filename));
					for(final ClientTcpTuple tuple : client.getSearchResult().get(filename)){
						_pnl.add(new JLabel(tuple.getInetAddress().getHostAddress()+":"+tuple.getPort()));
						JButton button = new JButton();
						button.addActionListener(new ActionListener() {
							@Override
							public void actionPerformed(ActionEvent e) {
								executor.execute(new Runnable() {
									@Override
									public void run() {
											try {
												fileSave(filename, tuple);
												lblStatusDownload.setForeground(Color.GREEN);
												lblStatusDownload.setText("Download successful");
											} catch (IOException e) {
												// TODO Auto-generated catch block
												e.printStackTrace();
											} catch (JAXBException e) {
												// TODO Auto-generated catch block
												e.printStackTrace();
											} catch (TestException e) {
												lblStatusDownload.setForeground(Color.RED);
												lblStatusDownload.setText("This peer does not share this file anymore");
											}
										
									}
								});
							}
						});
						_pnl.add(button);
					}
					_panelResult.add(_pnl);
				}
				centerPanel.add(_panelResult, BorderLayout.CENTER);
				centerPanel.add(lblStatusDownload, BorderLayout.SOUTH);
			}
			pack();
			txtSearch.requestFocusInWindow();
			repaint();
		}
	}

	/**
	 *  
	 */
	private void unregister(){
		if(client.isRegistered()){
			client.unshare();	
		}
		System.exit(0);
	}
	
	@Override
	public void actionPerformed(ActionEvent arg0) {
		if(arg0.getSource() == menuQuit){
			executor.execute(new Runnable() {	
				@Override
				public void run() {
					unregister();
				}
			});
		}
		if(arg0.getSource() == menuParameters){
			new ClientUI_Parameters(client);
		}
		if(arg0.getSource() == menuShareByMe){
			if(toDisplay != FILE_I_SHARE){
				toDisplay = FILE_I_SHARE;
				centerPanel();
			}
			
		}
		if(arg0.getSource() == menuShareByAll){
			toDisplay = FILE_ALL_SHARE;
			centerPanel();
		}
		if(arg0.getSource() == menuPeerOnTheServer){
			toDisplay = PEER_ON_SERVER;
			centerPanel();
		}
		if(arg0.getSource() == menuSearch){
			toDisplay = SEARCH;
			centerPanel();
		}
		if(arg0.getSource() == btnSubmitSearch){
			executor.execute(new Runnable() {
				
				@Override
				public void run() {
					client.searchRequest(txtSearch.getText());
				}
			});
		}
	}
	
	@Override
	public void windowActivated(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowClosed(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		executor.execute(new Runnable() {			
			@Override
			public void run() {
				unregister();
			}
		});
		
	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowIconified(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowOpened(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		System.out.println("update received from"+arg0);
		if(arg0.getClass() == Client.class){
			if(client.isRegistered()){
				lblStatus.setText("Files are shared ("+client.getSharedFiles().size()+" files)");
			}
			else {
				lblStatus.setText("Files are not shared ("+client.getSharedFiles().size()+" files)");
			} 
			centerPanel();
			repaint();
		}
	}
	
	private void fileSave(String filename,ClientTcpTuple tuple) throws IOException, JAXBException, TestException {
		JFileChooser fic = new JFileChooser();
		fic.setCurrentDirectory(new File(client.getSharedFolderPath()));
		fic.setSelectedFile(new File(filename));
		int returnVal = fic.showSaveDialog(this);
		if(returnVal == JFileChooser.APPROVE_OPTION) {
			File solFile = fic.getSelectedFile();
			if (solFile.exists()){
				int answer = JOptionPane.showConfirmDialog(
						this, solFile.getName() +" already exists " + "\n" + "Do you want to replace it?",null,
						JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE
				);
				if (answer != JOptionPane.OK_OPTION)
					return;  
			}
			client.retrieveFile(filename, tuple, solFile);
		}
	}
}
